package gonet

import (
	"fmt"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/decoder"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/heartbeat"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/pack"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/request"
	//"git.gz.internal.jumaiyx.cn/pkg/tnet/response"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/route"
	"github.com/panjf2000/gnet/v2"
	bbPool "github.com/panjf2000/gnet/v2/pkg/pool/bytebuffer"
	goPool "github.com/panjf2000/gnet/v2/pkg/pool/goroutine"
	"time"
)

type Connect struct {
	frameDecoder decoder.FrameDecoder
	heartbeat    heartbeat.Heartbeat
}

type TcpServer struct {
	pool      *goPool.Pool
	apis      map[uint32]route.IRouter
	heartbeat hb
	//connection connection.ConnMatrix
	connStart     func(c gnet.Conn)            // 客户端建立连接时执行的方法
	connStop      func(c gnet.Conn)            // 客户端断开连接时执行的方法
	connIntercept func(request.IRequest) error // 请求拦截时执行的方法
}

// OnBoot 当引擎准备好接受连接时，将触发。
// //参数引擎具有信息和各种实用程序。
func (ts *TcpServer) OnBoot(eng gnet.Engine) (action gnet.Action) {
	fmt.Println("OnBoot")
	return
}

// OnShutdown 当发动机关闭时发生火灾，它在
// 所有事件循环和连接都关闭。
func (ts *TcpServer) OnShutdown(eng gnet.Engine) {
	fmt.Println("OnShutdown")
}

// OnOpen 在打开新连接时激发。
//
// Conn c具有有关连接的信息，例如其本地和远程地址。
// 参数out是将要发送回对等方的返回值。
// 通常不建议在OnOpen中将大量数据发送回对等端。
func (ts *TcpServer) OnOpen(c gnet.Conn) (out []byte, action gnet.Action) {
	//fmt.Println("fd:", c.Fd())
	//es.connection.AddConn(c)
	if ts.connStart != nil {
		ts.connStart(c)
	}
	//fmt.Println("OnOpen")
	// 开启心跳监听
	var hbt heartbeat.Heartbeat
	if ts.heartbeat.router != nil {
		//fmt.Println("开启心跳监听")
		hbt = heartbeat.NewHeartbeat(c, ts.heartbeat.msgID, ts.heartbeat.router, ts.heartbeat.interval)
		hbt.Start()
	}
	c.SetContext(&Connect{
		frameDecoder: decoder.NewFrameDecoder(),
		heartbeat:    hbt,
	})
	return
}

// OnClose 当连接关闭时激发。
// 参数err是最后一个已知的连接错误。
func (ts *TcpServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
	connect := c.Context().(*Connect)
	if ts.connStop != nil {
		ts.connStop(c)
	}
	//fmt.Println(c.Fd(), ":OnClose")
	//es.connection.DelConn(c)
	//fmt.Println("OnClose fd len:", es.connection.LoadCount())
	// 停止心跳监听
	if connect.heartbeat != nil {
		fmt.Println(c.Fd(), ":关闭心跳监听")
		connect.heartbeat.Stop()
	}
	return
}

// OnTraffic 套接字从对等端接收数据时激发。
//
// 注意，从Conn.Peek（int）/Conn.Next（int）返回的[]字节不允许传递到新的goroutine，
// 因为在OnTraffic（）返回后，这个[]字节将在事件循环中重复使用。
// 如果必须在新的goroutine中使用这个[]字节，则应该复制它或调用Conn.Read（[]字节）
// 要将数据读取到您自己的[]字节中，请将新的[]字节传递给新的goroutine。
func (ts *TcpServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
	buf := bbPool.Get()
	_, _ = c.WriteTo(buf)
	code := c.Context().(*Connect)
	//fmt.Println("OnTraffic fd len:", es.connection.LoadCount())
	frameDecoder := code.frameDecoder.Decoder(buf.Bytes())
	//fmt.Println("fd:", c.Fd())
	_ = ts.pool.Submit(func() {
		for _, bytes := range frameDecoder {
			message := pack.NewMessage(bytes, pack.TCP)
			if message == nil {
				//  数据包不完成
				continue
			}
			iRequest, cancel := request.NewRequest(c, message)
			defer cancel()
			if ts.connIntercept != nil {
				err := ts.connIntercept(iRequest)
				if err != nil {
					//_ = response.Error(c, err)
					_ = c.Close()
					return
				}
			}
			// 找到指定路由
			router, ok := ts.apis[message.GetMsgId()]
			if !ok {
				fmt.Println("未找到路由：", message.GetMsgId())
				//_ = response.ErrorNotRoute(c)
				_ = c.Close()
				continue
			}
			router.PreHandle(iRequest)
			router.Handle(iRequest)
			router.PostHandle(iRequest)
		}
	})

	return
}

// OnTick 发动机启动后立即点火，并将再次点火
// 在延迟返回值指定的持续时间之后。
func (ts *TcpServer) OnTick() (delay time.Duration, action gnet.Action) {
	//fmt.Println("OnTick")
	delay = time.Second * 10
	//action = gnet.Shutdown
	return
}
